﻿//==============================================================================================
//Author: Uncle Song
//Create Date: 2022-06-30
//Description: 贝塞尔曲线创建
//----------------------------------------------------------------------------------------------
//Alter History:
//              2022-06-30  add Codes.
//============================================================================================== 

using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;

namespace FrameWorkSong
{
    public class BasselPath
    {
        List<GameObject> piont = new List<GameObject>();
        GameObject mianPiont;
        GameObject frontPiont;
        GameObject backePiont;
        public BasselPath(float radius, float armLength)
        {
            mianPiont = new GameObject();
            mianPiont.transform.position = Vector3.zero;
            frontPiont = new GameObject();
            frontPiont.transform.position = Vector3.zero + (Vector3.right * armLength);

            backePiont = new GameObject();
            backePiont.transform.position = Vector3.zero + (Vector3.left * armLength);

            piont.Add(frontPiont);
            piont.Add(mianPiont);
            piont.Add(backePiont);
            backePiont.transform.SetParent(mianPiont.transform);
            frontPiont.transform.SetParent(mianPiont.transform);
            mianPiont.AddComponent<DrawGizmosPoint>().myRadius = radius;
            frontPiont.AddComponent<DrawGizmosPoint>().myRadius = radius;
            backePiont.AddComponent<DrawGizmosPoint>().myRadius = radius;
        }

        public GameObject MianPiont { get => mianPiont; set => mianPiont = value; }
        public GameObject FrontPiont { get => frontPiont; }
        public GameObject BackePiont { get => backePiont; }
        public List<GameObject> Piont { get => piont; }
    }



    /// <summary>
    /// 绘制节点
    /// </summary>
    public class DrawGizmosPoint : MonoBehaviour
    {

        public float myRadius = 1;
        private void OnDrawGizmos()
        {
            // List<Vector3> controlPointPos = SelfPoint.Select(point => point.transform.position).ToList();

            //绘制点
            Gizmos.color = Color.blue;

            Gizmos.DrawSphere(transform.position, myRadius);



        }
    }
    /// <summary>
    /// 绘制节点线
    /// </summary>
    public class DrawGizmosPointLine : MonoBehaviour
    {
        public float radius = 1;
        public List<GameObject> SelfPoint = new List<GameObject>();
        private void OnDrawGizmos()
        {
            List<Vector3> controlPointPos = SelfPoint.Select(point => point.transform.position).ToList();



            //绘制曲线控制点连线
            Gizmos.color = Color.red;
            for (int i = 0; i < controlPointPos.Count - 1; i += 3)
            {
                Gizmos.DrawLine(controlPointPos[i], controlPointPos[i + 1]);
                Gizmos.DrawLine(controlPointPos[i + 1], controlPointPos[i + 2]);
            }
        }
    }
    /// <summary>
    /// 绘制曲线
    /// </summary>
    public class DrawGizmosLine : MonoBehaviour
    {
        public float radius;
        public int densityCurve;
        public List<GameObject> SelfPoint;
        public List<Vector3> CurvePoints;
        private void OnDrawGizmos()
        {
            List<Vector3> controlPointPos = SelfPoint.Select(point => point.transform.position).ToList();
            if (controlPointPos != null)
            {
                CurvePoints = GetDrawingPoints(controlPointPos, densityCurve);
            }

            //绘制曲线
            if (CurvePoints.Count >= 4)
            {
                Gizmos.color = Color.green;
                //点密度
                foreach (var item in CurvePoints)
                {
                    Gizmos.DrawSphere(item, radius * 0.5f);
                }
                //曲线
                for (int i = 0; i < CurvePoints.Count - 1; i++)
                {
                    Gizmos.DrawLine(CurvePoints[i], CurvePoints[i + 1]);
                }
            }


        }
        /// <summary>
        /// 获取绘制点
        /// </summary>
        /// <param name="controlPoints"></param>
        /// <param name="segmentsPerCurve"></param>
        /// <returns></returns>
        public List<Vector3> GetDrawingPoints(List<Vector3> controlPoints, int segmentsPerCurve)
        {
            List<Vector3> points = new List<Vector3>();
            // 下一段的起始点和上段终点是一个，所以是 i+=3
            for (int i = 1; i < controlPoints.Count - 4; i += 3)
            {

                var p0 = controlPoints[i];
                var p1 = controlPoints[i + 1];
                var p2 = controlPoints[i + 2];
                var p3 = controlPoints[i + 3];
                float dis = Vector3.Distance(p0, p3);
                int count = Mathf.CeilToInt(segmentsPerCurve * dis);
                if (count < segmentsPerCurve)
                {
                    count = segmentsPerCurve;
                }

                for (int j = 0; j <= count; j++)
                {
                    var t = j / (float)count;
                    points.Add(CalculateBezierPoint(t, p0, p1, p2, p3));
                }
            }
            return points;
        }
        // 三阶公式
        Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
        {
            Vector3 result;

            Vector3 p0p1 = (1 - t) * p0 + t * p1;
            Vector3 p1p2 = (1 - t) * p1 + t * p2;
            Vector3 p2p3 = (1 - t) * p2 + t * p3;

            Vector3 p0p1p2 = (1 - t) * p0p1 + t * p1p2;
            Vector3 p1p2p3 = (1 - t) * p1p2 + t * p2p3;

            result = (1 - t) * p0p1p2 + t * p1p2p3;
            return result;
        }

    }
#if UNITY_EDITOR
    public class BesselPathCreat : ScriptableWizard
    {
        public string Name = "Path";
        // 点的半径
        public float radius = 1;
        // 摇臂半径
        public float armLength = 1;
        // 曲线取点的密度
        public int densityCurve = 1;
        /// <summary>
        /// 绘制曲线控制点 -- 此脚本的子物体
        /// </summary>
        public List<GameObject> PathPointList = new List<GameObject>();

        DrawGizmosLine drawGizmosLint;
        GameObject game;

        [MenuItem("FrameWorkSong/FrameWork/3.创建贝塞尔路径", false, 3)]
        static void CreateBasselPath()
        {
            ScriptableWizard.DisplayWizard<BesselPathCreat>("CreateBasselPath", "创建", "加点");

        }
        /// <summary>
        /// 创建按钮触发
        /// </summary>
        void OnWizardCreate()
        {
            if (PathPointList.Count > 4)
            {
                var level = ScriptableObject.CreateInstance<BasselPathTemplet>();
                level.BasselPathPoints = drawGizmosLint.CurvePoints;
                AssetDatabase.CreateAsset(level, @"Assets/FrameWorkSong/Data/" + Name + ".asset");//在传入的路径中创建资源
                AssetDatabase.SaveAssets(); //存储资源
                AssetDatabase.Refresh(); //刷新

            }


            DestroyObject();
        }
        /// <summary>
        /// 关闭触发
        /// </summary>
        void DestroyObject()
        {
            if (game)
            {
                DestroyImmediate(game);
            }
            for (int i = 0; i < PathPointList.Count; i++)
            {
                DestroyImmediate(PathPointList[i]);
            }
        }
        void OnWizardUpdate()
        {

        }
        /// <summary>
        /// 加点按钮触发
        /// </summary>
        // When the user presses the "Apply" button OnWizardOtherButton is called.
        void OnWizardOtherButton()
        {

            if (PathPointList.Count == 0)
            {
                game = new GameObject();
                drawGizmosLint = game.AddComponent<DrawGizmosLine>();
            }
            BasselPath basselPath = new BasselPath(radius, armLength);
            DrawGizmosPointLine drawGizmos = basselPath.MianPiont.AddComponent<DrawGizmosPointLine>();
            PathPointList.Add(basselPath.FrontPiont);
            PathPointList.Add(basselPath.MianPiont);
            PathPointList.Add(basselPath.BackePiont);
            drawGizmos.SelfPoint = basselPath.Piont;
            drawGizmosLint.SelfPoint = PathPointList;
            drawGizmosLint.densityCurve = densityCurve;
            drawGizmosLint.radius = radius;
        }
        void OnDestroy()
        {
            DestroyObject();
        }


    }
#endif
}
